﻿<%
'''模版引擎类,使用Sa来统筹
Class Ashapo_Tpl_Class
	'RegExp对象
	Private s_regex
	'''双引号替代符
	Private s_dqmarkstr
	'''单引号替代符
	Private s_sqmarkstr
	'''Literal标签收集器,Literal标签收集器key前缀,收集个数
	Private s_collector, s_collectorPre, s_colli
	'''当前G/M/A/T
	Private s_nowG, s_nowM, s_nowA, s_nowT
	
	'''构造
	Private Sub Class_Initialize()
		s_dqmarkstr = "~"
		s_sqmarkstr = "`"
		Set s_regex = New RegExp
		s_regex.Global = True
		s_regex.IgnoreCase = True
		s_regex.Multiline = False
		's_collectorPre不能包含正则元字符,且不能与模板中的任何字符串相同
		s_collectorPre = "%ashapocoll%"
		s_colli = 0
		Set s_collector = Server.CreateObject(C_DicName)
		'获取GMAT信息
		s_nowG = G("g:s:" & C_DefGroup)
		s_nowM = G("m:s:" & C_DefModule)
		s_nowA = G("a:s:" & C_DefAction)
		s_nowT = C_DefTplName
	End Sub
	
	'''析构
	Private Sub Class_Terminate()
		'模板解析析构
		Set s_regex = Nothing
		Set s_collector = Nothing
	End Sub
	
	'''设置双引号替换字符
	'不能使用$和常用字符，不能与已有字符串发生冲突
	'考虑废弃
	'p_s:用作双引号替代的字符
	Public Property Let DqMarkStr(Byval p_s)
		s_dqmarkstr = p_s
	End Property

	'''设置单引号替换字符
	'不能使用$和常用字符，不能与已有字符串发生冲突
	'考虑废弃
	'p_s:用作单引号替代的字符
	Public Property Let SqMarkStr(Byval p_s)
		s_sqmarkstr = p_s
	End Property
	
	'''根据整个xml节点属性字符串获取相关属性值
	'p_s:整个xml节点的字符串
	'p_a:属性名称
	'p_d:为空时的默认值
	Private Function getAttr_(Byval p_s, Byval p_a, Byval p_d)
		s_regex.Pattern = "[\s\S]*[\s]*" & p_a & "[\s]*=[\s]*['|" & Chr(34) & "]?[\s]*([^'" & Chr(34) & "]*)[\s]*['|" & Chr(34) & "]?"
		Dim t_c : Set t_c = s_regex.Execute(p_s)
		If t_c.Count = 1 Then
			getAttr_ = t_c(0).SubMatches(0)
		Else
			getAttr_ = ""
		End If
		If getAttr_ = "" Then
			getAttr_ = p_d
		End If
		'还原双引号和单引号
		getAttr_ = Replace(getAttr_, s_dqmarkstr, """")
		getAttr_ = Replace(getAttr_, s_sqmarkstr, "'")
		Set t_c = Nothing
	End Function
	
	'''将$var转化为var,即去掉前面的$(如第一个字符不是$则原样返回)
	'p_v:要转换的字符串
	Private Function toVar_(Byval p_v)
		If Left(p_v,1) = "$" Then
			toVar_ = Right(p_v, Len(p_v)-1)
		Else
			toVar_ = p_v
		End If
	End Function
	
	'''收集Literal标签内容
	'解析Literal标签的过程包括收集和恢复两部分
	'仅解析最外层Literal,这样内层Literal也可以原样输出
	'p_s:要解析的模板代码
	Private Function sjLiteral_(Byval p_s)
		s_regex.Pattern = "<literal[^>]*[\s]*>[\s]*[\n]?(((?!<literal(.|\n))(.|\n)(?!literal>))+)<\/literal>[\s]*[\n]?"
		Dim t_r : Set t_r = New RegExp
		t_r.Global = True
		t_r.IgnoreCase = True
		t_r.Multiline = False
		t_r.Pattern = "~" & s_collectorPre & "([\d]?)~"
		Dim t_i, t_v, t_t
		Dim t_c, t_m : Set t_m = s_regex.Execute(p_s)
		For Each t_c In t_m
			't_v = t_c.SubMatches(0)
			t_v = t_c.Value
			'开始收集
			s_colli = s_colli + 1
			'本次匹配字符串内已有之前匹配的Literal标签，则应进行还原
			Set t_t = t_r.Execute(t_v)
			For Each t_i In t_t
				If s_collector.Exists("~" & s_collectorPre & t_i.SubMatches(0) & "~") Then
					t_v = Replace(t_v, "~" & s_collectorPre & t_i.SubMatches(0) & "~", s_collector("~" & s_collectorPre & t_i.SubMatches(0) & "~"))
					s_collector.Remove("~" & s_collectorPre & t_i.SubMatches(0) & "~")
				End If
			Next
			Set t_t = Nothing
			s_collector("~" & s_collectorPre & Cstr(s_colli) & "~") = t_v
			p_s = Replace(p_s, t_c.Value, "~" & s_collectorPre & Cstr(s_colli) & "~")
		Next
		Set t_m = Nothing
		If s_regex.Test(p_s) Then
			sjLiteral_ = sjLiteral_(p_s)
		Else
			sjLiteral_ = p_s
		End If
	End Function
	
	'''恢复Literal标签内容
	'解析Literal标签的过程包括收集和恢复两部分
	'p_s:要解析的模板代码
	Private Function hfLiteral_(Byval p_s)
		Dim t_k, t_s
		If Has(s_collector) Then
			For Each t_k In s_collector
				'剔除最外层的Literal标签
				t_s = s_collector(t_k)
				t_s = Right(t_s, Len(t_s)-InStr(t_s, ">"))
				t_s = Left(t_s, InStrRev(t_s, "<")-1)
				'删除可能出现的换行
				If InStr(t_s, vbcrlf) = 1 Then
					t_s = Replace(t_s,vbcrlf,"",1,1)
				End If
				p_s = Replace(p_s,t_k,t_s)
			Next
		End If
		hfLiteral_ = p_s
	End Function
	
	'''解析Include标签
	'file:文件路径
	'路径分析:
	'1:完整路径，以"/"作为开头
	'2:当前模块模版(read)
	'3:其他模块模板(public:header)
	'4:其他分组模块模板(admin:user:read)
	'5:其他主题分组模块模板,不建议使用(bule:admin:user:read)
	'p_s:要解析的模板代码
	Private Function jxInclude_(Byval p_s)
		s_regex.Pattern = "<include[\s]+([^>]*)[\s]*[\/]?[\s]*>"
		Dim t_mc : Set t_mc = s_regex.Execute(p_s)
		Dim t_ma, t_f, t_t, t_g, t_m, t_a
		Dim t_a1, t_a2, t_a3, t_tp
		t_tp = "/" & C_AppFolder & "/" & C_TplFolder & "/" & s_nowT & "/" & s_nowG
		t_tp = t_tp & "/" & s_nowM & "/" & s_nowA & C_TplExtSuf
		t_a = Split(t_tp, "/")
		t_t = t_a(3)
		t_g = t_a(4)
		t_m = t_a(5)
		For Each t_ma In t_mc
			t_f = getAttr_(t_ma.SubMatches(0), "file", "")
			t_f = Replace(t_f, "\", "/")
			If t_f = "" Then
				Sa.E.Throw(43)
			End If
			If Not Left(t_f,1) = "/" Then
				t_a1 = ParamRev(t_f)
				t_a = t_a1(0)
				If Has(t_a1(1)) Then
					t_a2 = ParamRev(t_a1(1))
					t_m = t_a2(0)
					If Has(t_a2(1)) Then
						t_a3 = ParamRev(t_a2(1))
						t_g = t_a3(0)
						If Has(t_a3(1)) Then
							t_t = t_a3(1)
						End If
					End If
				End If
				t_f = "/" & C_AppFolder & "/" & C_TplFolder & "/" & t_t & "/" & t_g & "/" & t_m & "/" & t_a & C_TplExtSuf
			End If
			If Sa.Fso.IsFile(t_f) Then
				p_s = Replace(p_s, t_ma.Value, Sa.Fso.ReadFile(t_f))
				'对每个新解析文件都应进行Literal标签收集
				p_s = sjLiteral_(p_s)
			Else
				Sa.E.Throw(44)
			End If
		Next
		Set t_mc = Nothing
		If s_regex.Test(p_s) Then
			jxInclude_ = jxInclude_(p_s)
		Else
			jxInclude_ = p_s
		End If
	End Function
	
	'''解析ForEach标签
	'''思路是先匹配最内层标签，然后进行递归
	'name:数组或对象名
	'item:循环变量名
	'key:循环增量
	'p_s:要解析的模板代码
	Private Function jxForEach_(Byval p_s)
		s_regex.Pattern = "<foreach[\s]+([^>]*)[\s]*>[\s]*[\n]?(((?!<foreach(.|\n))(.|\n)(?!foreach>))+)<\/foreach>[\s]*[\n]?"
		Dim t_mc : Set t_mc = s_regex.Execute(p_s)
		Dim t_s, t_m, t_item, t_name, t_key
		For Each t_m In t_mc
			t_item = getAttr_(t_m.SubMatches(0), "item", "x")
			t_name = toVar_(getAttr_(t_m.SubMatches(0), "name", ""))
			If t_name = "" Then
				Sa.E.Throw(31)
			End If
			t_key = getAttr_(t_m.SubMatches(0), "key", "i")
			t_s = ""
			t_s = t_s & "<" & Chr(37) & vbcrlf & "Dim " & t_key & " : " & t_key & " = 0" & vbcrlf
			t_s = t_s & "For Each " & t_item & " In " & t_name & vbcrlf
			t_s = t_s & t_key & " = " & t_key & " + 1" & vbcrlf & Chr(37) & ">"
			t_s = t_s & t_m.SubMatches(1)
			t_s = t_s & "<" & Chr(37) & vbcrlf & "Next" & vbcrlf & Chr(37) & ">"
			p_s = Replace(p_s, t_m.Value, t_s)
		Next
		Set t_mc = Nothing
		If s_regex.Test(p_s) Then
			jxForEach_ = jxForEach_(p_s)
		Else
			jxForEach_ = p_s
		End If
	End Function
	
	'''解析For标签
	'name:变量名
	'start:开始增量
	'end:结束增量
	'step:步进增量
	'p_s:要解析的模板代码
	Private Function jxFor_(Byval p_s)
		s_regex.Pattern = "<for[\s]+([^>]*)[\s]*>[\s]*[\n]?(((?!<for(.|\n))(.|\n)(?!for>))+)<\/for>[\s]*[\n]?"
		Dim t_mc : Set t_mc = s_regex.Execute(p_s)
		Dim t_s, t_m, t_start, t_end, t_name, t_step
		For Each t_m In t_mc
			t_start = getAttr_(t_m.SubMatches(0), "start", "1")
			t_end = getAttr_(t_m.SubMatches(0), "end", "")
			If t_end = "" Then
				Sa.E.Throw(32)
			End If
			t_step = getAttr_(t_m.SubMatches(0), "step", "1")
			t_name = getAttr_(t_m.SubMatches(0), "name", "i")
			t_s = ""
			t_s = t_s & "<" & Chr(37) & vbcrlf & "For " & t_name & "=" & t_start & " To " & t_end & " Step " & t_step & vbcrlf & Chr(37) & ">"
			t_s = t_s & t_m.SubMatches(1)
			t_s = t_s & "<" & Chr(37) & vbcrlf & "Next" & vbcrlf & Chr(37) & ">"
			p_s = Replace(p_s, t_m.Value, t_s)
		Next
		Set t_mc = Nothing
		If s_regex.Test(p_s) Then
			jxFor_ = jxFor_(p_s)
		Else
			jxFor_ = p_s
		End If
	End Function
	
	'''解析Record标签,用于输出数据集
	'type:1\rs指向记录集,2\sql指向查询语句.默认值为1
	'sqlstr:type为2\sql时，此项为必须值,查询语句变量名
	'zero:新增,开始时计数是否归零,1\true\yes为是,0\false\no为否,默认为1
	'name:记录集名称,最好是指定，默认为rs
	'length：输出记录集的个数,为空为不限制
	'key：循环key变量,默认值为i
	'mod:对key值取模，默认为2(暂时不实现)
	'conn:数据源的连接,默认Db.conn(type为2\sql时应尽量显式指定)
	'close:2\all循环结束关闭记录集析构,1\true\yes循环结束后关闭记录集,0\false\no循环结束后不关闭记录集(代码手动关闭,建议少用),默认为1
	'p_s:要解析的模板代码
	Private Function jxRecord_(Byval p_s)
		s_regex.Pattern = "<record[\s]+([^>]*)[\s]*>[\s]*[\n]?(((?!<record(.|\n))(.|\n)(?!record>))+)<\/record>[\s]*[\n]?"
		Dim t_mc : Set t_mc = s_regex.Execute(p_s)
		Dim t_s, t_m, t_type, t_name, t_length, t_key, t_mod, t_close, t_sqlstr, t_zero
		For Each t_m In t_mc
			t_type = getAttr_(t_m.SubMatches(0), "type", "1")
			t_name = toVar_(getAttr_(t_m.SubMatches(0), "name", "rs"))
			t_length = toVar_(getAttr_(t_m.SubMatches(0), "length", ""))
			t_key = toVar_(getAttr_(t_m.SubMatches(0), "key", "i"))
			t_mod = toVar_(getAttr_(t_m.SubMatches(0), "mod", "2"))
			t_conn = toVar_(getAttr_(t_m.SubMatches(0), "conn", "Db.Conn"))
			t_close = getAttr_(t_m.SubMatches(0), "close", "1")
			t_zero = getAttr_(t_m.SubMatches(0), "zero", "1")
			t_s = ""
			Select Case LCase(Trim(Cstr(t_type)))
			Case "1","rs"
				t_s = t_s & "<" & Chr(37) & vbcrlf
				'计数初始化
				If Cstr(t_zero) = "1" Or Lcase(t_zero) = "true" Or Lcase(t_zero) = "yes" Then
					t_s = t_s & "Dim "  & t_key & " : " & t_key & " = 0" & vbcrlf
				End If
				t_s = t_s & "Do While Not " & t_name & ".Eof" & vbcrlf
				t_s = t_s & t_key & " = " & t_key & " + 1" & vbcrlf
				t_s = t_s & Chr(37) & ">"
				t_s = t_s & t_m.SubMatches(1)
				t_s = t_s & "<" & Chr(37) & vbcrlf
				If Has(t_length) Then
					t_s = t_s & "If " & t_key & " >= " & t_length & " Then Exit Do" & vbcrlf
				End If
				t_s = t_s & t_name & ".MoveNext" & vbcrlf
				t_s = t_s & "Loop" & vbcrlf
				Select Case LCase(Trim(Cstr(t_close)))
				Case "0","false","no"
					'Do Nothing
				Case "1","true","yes"
					t_s = t_s & t_name & ".Close" & vbcrlf
				Case "2","all"
					t_s = t_s & t_name & ".Close" & vbcrlf
					t_s = t_s & "Set " & t_name & " = Nothing" & vbcrlf
				End Select
				t_s = t_s & Chr(37) & ">"
			Case "2","sql"
				t_sqlstr = toVar_(getAttr_(t_m.SubMatches(0), "sqlstr", ""))
				If t_sqlstr = "" Then
					'Response.Write("Found Err. The SqlStr Must Be Have!")
					'Response.End
					Sa.E.Throw(33)
				End If
				t_s = t_s & "<" & Chr(37) & vbcrlf
				'析构之前的连接
				t_s = t_s & "If TypeName(" & t_name & ") = " & Chr(34) & "Recordset" & Chr(34) & " Then" & vbcrlf
				t_s = t_s & "If " & t_name & ".State <> 0 Then" & vbcrlf
				t_s = t_s & t_name & ".Close" & vbcrlf
				t_s = t_s & "End If" & vbcrlf
				'如果不是,那就建立
				t_s = t_s & "Else" & vbcrlf
				t_s = t_s & "Set " & t_name & " = Server.Createobject(" & Chr(34) & "Adodb.Recordset" & Chr(34) & ")" & vbcrlf
				t_s = t_s & "End If" & vbcrlf
				'建立连接
				t_s = t_s & t_name & ".Open " & t_sqlstr & ", " & t_conn & vbcrlf
				''''''''重复代码应精简
				'计数初始化
				If Cstr(t_zero) = "1" Or Lcase(t_zero) = "true" Or Lcase(t_zero) = "yes" Then
					t_s = t_s & "Dim "  & t_key & " : " & t_key & " = 0" & vbcrlf
				End If
				t_s = t_s & "Do While Not " & t_name & ".Eof" & vbcrlf
				t_s = t_s & t_key & " = " & t_key & " + 1" & vbcrlf
				t_s = t_s & Chr(37) & ">"
				t_s = t_s & t_m.SubMatches(1)
				t_s = t_s & "<" & Chr(37) & vbcrlf
				If IsNumeric(t_length) Then
					t_s = t_s & "If " & t_key & " >= " & t_length & " Then Exit Do" & vbcrlf
				End If
				t_s = t_s & t_name & ".MoveNext" & vbcrlf
				t_s = t_s & "Loop" & vbcrlf
				Select Case LCase(Trim(Cstr(t_close)))
				Case "0","false","no"
					'Do Nothing
				Case "1","true","yes"
					t_s = t_s & t_name & ".Close" & vbcrlf
				Case "2","all"
					t_s = t_s & t_name & ".Close" & vbcrlf
					t_s = t_s & "Set " & t_name & " = Nothing" & vbcrlf
				End Select
				t_s = t_s & Chr(37) & ">"
			Case Else
				'出错处理
				Sa.E.Throw(34)
			End Select
			p_s = Replace(p_s, t_m.Value, t_s)
		Next
		Set t_mc = Nothing
		If s_regex.Test(p_s) Then
			jxRecord_ = jxRecord_(p_s)
		Else
			jxRecord_ = p_s
		End If
	End Function
	
	'''解析Switch标签,包括开始标签、结束标签、case标签、caseelse/default标签
	'select标签无嵌套问题
	'value有双引号转换问题(字符串包含双引号使用Chr(34)来解决,逗号Chr(44)), 添加辨别标签避免双引号转换问题
	'属性type用于标识value值类型(数字、字符串、变量)
	'type可能值:1、str(字符串)/2、num(数字)/3、var(变量)/多值1,2,3
	'未指定type时,对value进行判断(多值匹配时type应尽量显式提供)
	'p_s:要解析的模板代码
	Private Function jxSwitch_(Byval p_s)
		Dim t_name, t_value, t_type, t_va, t_vs, t_ta
		Dim t_mc, t_m, t_n, t_v, t_s, t_i
		'<switch name="var">
		s_regex.Pattern = "<switch[\s]+([^>]*)[\s]*>[\s]*[\n]?"
		Set t_mc = s_regex.Execute(p_s)
		For Each t_m In t_mc
			t_name = toVar_(getAttr_(t_m.SubMatches(0), "name", ""))
			If t_name = "" Then
				Sa.E.Throw(45)
			End If
			t_s = "<" & Chr(37) & "Select Case " & t_name & Chr(37)  & ">"
			p_s = Replace(p_s, t_m.Value, t_s)
		Next
		'<case value="1,2,3" type="1" />
		s_regex.Pattern = "<case[\s]+([^>]*)[\s]*[\/]?[\s]*>[\s]*[\n]?"
		Set t_mc = s_regex.Execute(p_s)
		For Each t_m In t_mc
			t_value = getAttr_(t_m.SubMatches(0), "value", "")
			'多值判断
			t_va = Split(t_value, ",")
			t_type = getAttr_(t_m.SubMatches(0), "type", "")
			t_ta = Split(t_type, ",")
			If UBound(t_ta) > 0 Then
				t_type = "arr"
				'多值格式个数不同引发错误
				If UBound(t_va) <> UBound(t_ta) Then
					Sa.E.Throw(46)
				End If
			End If
			If t_value = "" Then
				t_s = "<" & Chr(37) & "Case """"" & Chr(37) & ">"
			Else
				t_s = ""
				'类型初始化
				t_n = False
				t_v = False
				'确认值类型
				If t_type = "" Then
					For Each t_vs In t_va
						If IsNumeric(t_vs) Then
							t_n = True
						End If
						If Left(t_vs, 1) = "$" Then
							t_v = True
						End If
					Next
					If t_n Then
						t_type = "num"
					ElseIf t_v Then
						t_type = "var"
					Else
						'默认为字符串
						t_type = "str"
					End If
				End If
				Select Case Lcase(t_type)
				Case "arr"
					'数组每个对应上
					For t_i = 0 To UBound(t_va)
						Select Case Lcase(Cstr(t_ta(t_i)))
						Case "1","str"
							t_s = t_s & Chr(34) & t_va(t_i) & Chr(34)
						Case "2","num"
							t_s = t_s & t_va(t_i)
						Case "3","var"
							t_s = t_s & toVar_(t_va(t_i))
						Case Else
							t_s = t_s & Chr(34) & t_va(t_i) & Chr(34)
						End Select
						If t_i <> UBound(t_va) Then
							t_s = t_s & ","
						End If
					Next
				Case "1","str"
					For t_i = 0 To UBound(t_va)
						t_s = t_s & Chr(34) & t_va(t_i) & Chr(34)
						If t_i <> UBound(t_va) Then
							t_s = t_s & ","
						End If
					Next
				Case "2","num"
					For t_i = 0 To UBound(t_va)
						t_s = t_s & t_va(t_i)
						If t_i <> UBound(t_va) Then
							t_s = t_s & ","
						End If
					Next
				Case "3","var"
					For t_i = 0 To UBound(t_va)
						t_s = t_s & toVar_(t_va(t_i))
						If t_i <> UBound(t_va) Then
							t_s = t_s & ","
						End If
					Next
				Case Else
					For t_i = 0 To UBound(t_va)
						t_s = t_s & Chr(34) & t_va(t_i) & Chr(34)
						If t_i <> UBound(t_va) Then
							t_s = t_s & ","
						End If
					Next
				End Select
				t_s = "<" & Chr(37) & "Case " & t_s & Chr(37) & ">"
			End If
			p_s = Replace(p_s, t_m.Value, t_s)
		Next
		'<caseelse/>
		s_regex.Pattern = "<caseelse[\s]*[\/]?[\s]*>[\s]*[\n]?"
		t_s = "<" & Chr(37) & "Case Else" & Chr(37) & ">"
		p_s = s_regex.Replace(p_s,t_s)
		'<default/>
		s_regex.Pattern = "<default[\s]*[\/]?[\s]*>[\s]*[\n]?"
		t_s = "<" & Chr(37) & "Case Else" & Chr(37) & ">"
		p_s = s_regex.Replace(p_s,t_s)
		'</switch>
		s_regex.Pattern = "<[\s]*[\/]{1}switch[\s]*>[\s]*[\n]?"
		t_s = "<" & Chr(37) & "End Select" & Chr(37) & ">"
		p_s = s_regex.Replace(p_s,t_s)
		Set t_mc = Nothing
		jxSwitch_ = p_s
	End Function
	
	'''解析Compare标签
	'属性name:要比较的变量名
	'属性value:要比较的值,支持变量
	'属性type:比较值的类型,为空时进行自动判断
	'属性math:运算(eq/equal/neq/notequal/gt/egt/lt/elt/heq/nheq)
	'p_s:要解析的模板代码
	Private Function jxCompare_(Byval p_s)
		Dim t_mc, t_m, t_name, t_value, t_type, t_math, t_s, t_symb
		'解析别名标签
		Dim t_bq, t_bqa : t_bqa = Split("eq,equal,neq,notequal,gt,egt,lt,elt,heq,nheq", ",")
		For Each t_bq In t_bqa
			s_regex.Pattern = "<" & t_bq & "[\s]+([^>]*)[\s]*[\/]?[\s]*>"
			t_s = "<compare $1 math=" & Chr(34) & t_bq & Chr(34) & ">"
			p_s = s_regex.Replace(p_s,t_s)
			s_regex.Pattern = "<[\s]*[\/]{1}" & t_bq & "[\s]*>"
			t_s = "</compare>"
			p_s = s_regex.Replace(p_s,t_s)
		Next
		s_regex.Pattern = "<compare[\s]+([^>]*)[\s]*[\/]?[\s]*>[\s]*[\n]?"
		Set t_mc = s_regex.Execute(p_s)
		For Each t_m In t_mc
			t_name = toVar_(getAttr_(t_m.SubMatches(0), "name", ""))
			t_value = getAttr_(t_m.SubMatches(0), "value", "")
			t_type = getAttr_(t_m.SubMatches(0), "type", "")
			t_math = getAttr_(t_m.SubMatches(0), "math", "eq")
			If t_name = "" Then
				Errc.Throw(47)
			End If
			If t_type = "" Then
				If IsNumeric(t_value) Then
					t_type = "num"
				ElseIf Left(t_value, 1) = "$" Then
					t_type = "var"
				Else
					t_type = "str"
				End If
			End If
			Select Case Lcase(Cstr(t_type))
			Case "1","str"
				t_value = Chr(34) & t_value & Chr(34)
			Case "2","num"
				'Do Nothing
			Case "3","var"
				t_value = toVar_(t_value)
			Case Else
				t_value = Chr(34) & t_value & Chr(34)
			End Select
			t_s = ""
			Select Case Lcase(t_math)
			Case "heq"
				t_s = "<" & Chr(37) & "If " & t_name & " = " & t_value & " And VarType(" & t_name & ") = VarType(" & t_value & ") Then" & Chr(37)  & ">"
			Case "nheq"
				t_s = "<" & Chr(37) & "If " & t_name & " <> " & t_value & " Or VarType(" & t_name & ") <> VarType(" & t_value & ") Then" & Chr(37)  & ">"
			Case "eq","equal"
				t_symb = " = "
			Case "neq","notequal"
				t_symb = " <> "
			Case "gt"
				t_symb = " > "
			Case "egt"
				t_symb = " >= "
			Case "lt"
				t_symb = " < "
			Case "elt"
				t_symb = " <= "
			Case Else
				t_symb = " = "
			End Select
			If t_s = "" Then
				t_s = "<" & Chr(37) & "If " & t_name & t_symb & t_value & " Then" & Chr(37)  & ">"
			End If
			p_s = Replace(p_s, t_m.Value, t_s)
		Next
		'</compare>
		s_regex.Pattern = "<[\s]*[\/]{1}compare[\s]*>[\s]*[\n]?"
		t_s = "<" & Chr(37) & "End If" & Chr(37) & ">"
		p_s = s_regex.Replace(p_s,t_s)
		Set t_mc = Nothing
		jxCompare_ = p_s
	End Function
	
	'''解析Range标签
	'属性name:要比较的变量名
	'属性value:要比较的值,支持变量
	'属性type:比较值的类型,为空时进行自动判断
	'属性math:运算(in/notin/nin/between/btw/notbetween/nbtw)
	'属性border:是否包含边界值,between类型可用,默认为True
	'对于in类型(包括in/notin/nin)支持arr的type属性,但是在多值时不建议使用,
	'如<in name="$nme" value="$arr,1,2,3" type="arr,num,num,num">可以正常解析,原理是将1,2,3加入到arr数组进行合并,然后进行in判断
	'p_s:要解析的模板代码
	Private Function jxRange_(Byval p_s)
		Dim t_bq, t_bqa : t_bqa = Split("in,notin,nin,between,btw,notbetween,nbtw", ",")
		Dim t_name, t_math, t_value, t_type, t_border, t_s, t_va, t_ta, t_a, t_aa, t_na
		Dim t_mc, t_m, t_i, t_bt1, t_bt2
		'解析别名标签
		For Each t_bq In t_bqa
			s_regex.Pattern = "<" & t_bq & "[\s]+([^>]*)[\s]*[\/]?[\s]*>"
			t_s = "<range $1 math=" & Chr(34) & t_bq & Chr(34) & ">"
			p_s = s_regex.Replace(p_s,t_s)
			s_regex.Pattern = "<[\s]*[\/]{1}" & t_bq & "[\s]*>"
			t_s = "</range>"
			p_s = s_regex.Replace(p_s,t_s)
		Next
		s_regex.Pattern = "<range[\s]+([^>]*)[\s]*[\/]?[\s]*>[\s]*[\n]?"
		Set t_mc = s_regex.Execute(p_s)
		For Each t_m In t_mc
			t_name = toVar_(getAttr_(t_m.SubMatches(0), "name", ""))
			t_math = Lcase(Trim(getAttr_(t_m.SubMatches(0), "math", "in")))
			t_value = getAttr_(t_m.SubMatches(0), "value", "")
			t_border = Lcase(Trim(getAttr_(t_m.SubMatches(0), "border", "True")))
			t_type = Lcase(Trim(Cstr(getAttr_(t_m.SubMatches(0), "type", ""))))
			'多值判断
			t_va = Split(t_value, ",")
			t_ta = Split(t_type, ",")
			If UBound(t_ta) > 0 Then
				t_type = "comp"
				'多值格式个数不同引发错误
				If UBound(t_va) <> UBound(t_ta) Then
					Sa.E.Throw(50)
				End If
			End If
			'确认各值类型,构建in类型的Array
			t_s = ""
			'最后组装的arr实体
			t_a = ""
			'最后附件的arr数组字符实体
			t_aa = ""
			Select Case t_type
			Case ""
				'为空时对每个值进行检测
				For t_i = 0 To UBound(t_va)
					t_na = True
					If IsNumeric(t_va(t_i)) Then
						t_s = t_s & t_va(t_i)
					ElseIf Left(t_va(t_i), 1) = "$" Then
						'如果是数组应进行额外处理
						If Eval("VarType(" & toVar_(t_va(t_i)) & ")") >= 8192 Then
							If UBound(t_va) = 0 Then
								'单个数组变量直接返回
								t_a = toVar_(t_va(t_i))
								Exit For
							Else
								t_na = False
								t_aa = t_aa & " Or IsIn(" & t_name & "," & toVar_(t_va(t_i)) & ")"
							End If
						Else
							t_s = t_s & toVar_(t_va(t_i))
						End If
					Else
						t_s = t_s & Chr(34) & t_va(t_i) & Chr(34)
					End If
					If t_na Then
						If t_i <> UBound(t_va) Then
							t_s = t_s & ","
						End If
					End If
				Next
			Case "1","str"
				For t_i = 0 To UBound(t_va)
					t_s = t_s & Chr(34) & t_va(t_i) & Chr(34)
					If t_i <> UBound(t_va) Then
						t_s = t_s & ","
					End If
				Next
			Case "2","num"
				For t_i = 0 To UBound(t_va)
					t_s = t_s & t_va(t_i)
					If t_i <> UBound(t_va) Then
						t_s = t_s & ","
					End If
				Next
			Case "3","var"
				For t_i = 0 To UBound(t_va)
					t_s = t_s & toVar_(t_va(t_i))
					If t_i <> UBound(t_va) Then
						t_s = t_s & ","
					End If
				Next
			Case "4","arr"
				If UBound(t_va) = 0 Then
					t_a = toVar_(t_value)
				Else
					For t_i = 0 To UBound(t_va)
						t_aa = t_aa & " Or IsIn(" & t_name & "," & toVar_(t_va(t_i)) & ")"
					Next
				End If
			Case "comp"
				'复杂类型
				For t_i = 0 To UBound(t_va)
					t_na = True
					Select Case Lcase(Trim(Cstr(t_ta(t_i))))
					Case "1","str"
						t_s = t_s & Chr(34) & t_va(t_i) & Chr(34)
					Case "2","num"
						t_s = t_s & t_va(t_i)
					Case "3","var"
						t_s = t_s & toVar_(t_va(t_i))
					Case "4", "arr"
						t_na = False
						t_aa = t_aa & " Or IsIn(" & t_name & "," & toVar_(t_va(t_i)) & ")"
					Case Else
						Sa.E.Throw(51)
					End Select
					If t_na Then
						If t_i <> UBound(t_va) Then
							t_s = t_s & ","
						End If
					End If
				Next
			Case Else
				Sa.E.Throw(51)
			End Select
			'决定最后Arr
			If t_a = "" Then
				If Right(t_s, 1) = "," Then
					t_s = Left(t_s, Len(t_s)-1)
				End If
				t_a = "Array(" & t_s & ")"
			End If
			'确定between类型的两个值
			If IsIn(t_math, Split("3,between,btw,4,notbetween,nbtw", ",")) Then
				If UBound(t_va)<>1 Then
					Sa.E.Throw(53)
				End If
				'between类型不能有arr存在
				If InStr(t_type, "arr") > 0 Then
					Sa.E.Throw(54)
				End If
				t_bt1 = Max(Split(t_s, ",")(0), Split(t_s, ",")(1))
				t_bt2 = Min(Split(t_s, ",")(0), Split(t_s, ",")(1))
			End If
			Select Case t_math
			Case "1","in"
				If t_aa = "" Then
					t_s = "<" & Chr(37) & "If IsIn(" & t_name & ", " & t_a & ") Then" & Chr(37)  & ">"
				Else
					t_s = "<" & Chr(37) & "If (IsIn(" & t_name & ", " & t_a & ")" & t_aa & ") Then" & Chr(37)  & ">"
				End If
			Case "2","notin","nin"
				If t_aa = "" Then
					t_s = "<" & Chr(37) & "If Not IsIn(" & t_name & ", " & t_a & ") Then" & Chr(37)  & ">"
				Else
					t_s = "<" & Chr(37) & "If Not (IsIn(" & t_name & ", " & t_a & ")" & t_aa & ") Then" & Chr(37)  & ">"
				End If
			Case "3","between","btw"
				If t_border = "1" Or t_border = "true" Or t_border="yes" Then
					'带边界值
					t_s = "<" & Chr(37) & "If " & t_name & " >= " & t_bt2 & " And " & t_name & "<= " & t_bt1 & " Then" & Chr(37)  & ">"
				Else
					'不带边界值
					t_s = "<" & Chr(37) & "If " & t_name & " > " & t_bt2 & " And " & t_name & "< " & t_bt1 & " Then" & Chr(37)  & ">"
				End If
			Case "4","notbetween","nbtw"
				If t_border = "1" Or t_border = "true" Or t_border="yes" Then
					'带边界值
					t_s = "<" & Chr(37) & "If Not (" & t_name & " >= " & t_bt2 & " And " & t_name & "<= " & t_bt1 & ") Then" & Chr(37)  & ">"
				Else
					'不带边界值
					t_s = "<" & Chr(37) & "If Not (" & t_name & " > " & t_bt2 & " And " & t_name & "< " & t_bt1 & ") Then" & Chr(37)  & ">"
				End If
			Case Else
				Sa.E.Throw(52)
			End Select
			p_s = Replace(p_s, t_m.Value, t_s)
		Next
		'</range>
		s_regex.Pattern = "<[\s]*[\/]{1}range[\s]*>[\s]*[\n]?"
		t_s = "<" & Chr(37) & "End If" & Chr(37) & ">"
		p_s = s_regex.Replace(p_s,t_s)
		Set t_mc = Nothing
		jxRange_ = p_s
	End Function
	
	'''解析Empty标签,包括(Empty/Notempty/Nempty)
	'属性name,要判断的值
	'p_s:要解析的模板代码
	Private Function jxEmpty_(Byval p_s)
		Dim t_m, t_mc, t_name, t_s
		'Empty标签
		s_regex.Pattern = "<empty[\s]+([^>]*)[\s]*[\/]?[\s]*>[\s]*[\n]?"		
		Set t_mc = s_regex.Execute(p_s)
		For Each t_m In t_mc
			t_name = toVar_(getAttr_(t_m.SubMatches(0), "name", ""))
			If t_name = "" Then
				Sa.E.Throw(55)
			End If
			t_s = "<" & Chr(37) & "If IsN(" & t_name & ") Then" & Chr(37)  & ">"
			p_s = Replace(p_s, t_m.Value, t_s)
		Next
		'Notempty/Nempty标签
		s_regex.Pattern = "<n(ot)?empty[\s]+([^>]*)[\s]*[\/]?[\s]*>[\s]*[\n]?"		
		Set t_mc = s_regex.Execute(p_s)
		For Each t_m In t_mc
			t_name = toVar_(getAttr_(t_m.SubMatches(1), "name", ""))
			If t_name = "" Then
				Sa.E.Throw(56)
			End If
			t_s = "<" & Chr(37) & "If Has(" & t_name & ") Then" & Chr(37)  & ">"
			p_s = Replace(p_s, t_m.Value, t_s)
		Next
		Set t_mc = Nothing
		'</empty>
		s_regex.Pattern = "<[\s]*[\/]{1}empty[\s]*>[\s]*[\n]?"
		t_s = "<" & Chr(37) & "End If" & Chr(37) & ">"
		p_s = s_regex.Replace(p_s,t_s)
		'</notempty></nempty>
		s_regex.Pattern = "<[\s]*[\/]{1}n(ot)?empty[\s]*>[\s]*[\n]?"
		t_s = "<" & Chr(37) & "End If" & Chr(37) & ">"
		p_s = s_regex.Replace(p_s,t_s)
		jxEmpty_ = p_s
	End Function
	
	'''解析Const标签
	'属性name,要定义的常量名
	'属性value,常量值
	'属性type,常量类型,仅支持num、str类型
	'需要进行复杂常量定义,请使用asp标签
	'p_s:要解析的模板代码
	Private Function jxConst_(Byval p_s)
		Dim t_m, t_mc, t_name, t_value, t_type, t_s
		s_regex.Pattern = "<const[\s]+([^>]*)[\s]*[\/]?[\s]*>[\s]*[\n]?"		
		Set t_mc = s_regex.Execute(p_s)
		For Each t_m In t_mc
			t_name = toVar_(getAttr_(t_m.SubMatches(0), "name", ""))
			t_value = getAttr_(t_m.SubMatches(0), "value", "")
			t_type = Lcase(Trim(Cstr(getAttr_(t_m.SubMatches(0), "value", ""))))
			If t_name = "" Then
				Sa.E.Throw(57)
			End If
			Select Case t_type
			Case ""
				If Not IsNumeric(t_value) Then
					t_value = Chr(34) & t_value & Chr(34)
				End If
			Case "1","str"
				t_value = Chr(34) & t_value & Chr(34)
			Case "2","num"
				'DoNothing
			Case Else
				Sa.E.Throw(58)
			End Select
			t_s = "<" & Chr(37) & "Const " & t_name & " = " & t_value & Chr(37)  & ">"
			p_s = Replace(p_s, t_m.Value, t_s)
		Next
		Set t_mc = Nothing
		jxConst_ = p_s
	End Function
	
	'''解析Dim标签
	'属性name,要定义的变量名
	'属性value,变量值
	'属性type,常量类型,仅支持num、str、var类型
	'需要进行复杂变量定义,请使用asp标签
	'p_s:要解析的模板代码
	Private Function jxDim_(Byval p_s)
		Dim t_m, t_mc, t_name, t_value, t_type, t_s
		s_regex.Pattern = "<dim[\s]+([^>]*)[\s]*[\/]?[\s]*>[\s]*[\n]?"		
		Set t_mc = s_regex.Execute(p_s)
		For Each t_m In t_mc
			t_name = toVar_(getAttr_(t_m.SubMatches(0), "name", ""))
			t_value = getAttr_(t_m.SubMatches(0), "value", "")
			t_type = Lcase(Trim(Cstr(getAttr_(t_m.SubMatches(0), "value", ""))))
			If t_name = "" Then
				Sa.E.Throw(59)
			End If
			Select Case t_type
			Case ""
				If Not IsNumeric(t_value) Then
					t_value = Chr(34) & t_value & Chr(34)
				End If
			Case "1","str"
				t_value = Chr(34) & t_value & Chr(34)
			Case "2","num"
				'DoNothing
			Case "3","var"
				t_value = toVar_(t_value)
			Case Else
				Sa.E.Throw(60)
			End Select
			t_s = "<" & Chr(37) & "Dim " & t_name & " : " & t_name & " = " & t_value & Chr(37)  & ">"
			p_s = Replace(p_s, t_m.Value, t_s)
		Next
		Set t_mc = Nothing
		jxDim_ = p_s
	End Function
	
	'''解析If标签,包括(If,ElseIf)
	'属性condition,返回类型为bool的变量或常量或函数,含运算符建议使用Compare标签
	'If标签主要用于单变量True判断
	'p_s:要解析的模板代码
	Private Function jxIf_(Byval p_s)
		Dim t_m, t_mc, t_condition, t_s
		'If标签
		s_regex.Pattern = "<if[\s]+([^>]*)[\s]*[\/]?[\s]*>[\s]*[\n]?"		
		Set t_mc = s_regex.Execute(p_s)
		For Each t_m In t_mc
			t_condition = toVar_(getAttr_(t_m.SubMatches(0), "condition", ""))
			If t_condition = "" Then
				Sa.E.Throw(48)
			End If
			t_s = "<" & Chr(37) & "If " & t_condition & " Then" & Chr(37)  & ">"
			p_s = Replace(p_s, t_m.Value, t_s)
		Next
		'ElseIf标签
		s_regex.Pattern = "<elseif[\s]+([^>]*)[\s]*[\/]?[\s]*>[\s]*[\n]?"		
		Set t_mc = s_regex.Execute(p_s)
		For Each t_m In t_mc
			t_condition = toVar_(getAttr_(t_m.SubMatches(0), "condition", ""))
			If t_condition = "" Then
				Sa.E.Throw(49)
			End If
			t_s = "<" & Chr(37) & "ElseIf " & t_condition & " Then" & Chr(37)  & ">"
			p_s = Replace(p_s, t_m.Value, t_s)
		Next
		Set t_mc = Nothing
		'</if>
		s_regex.Pattern = "<[\s]*[\/]{1}if[\s]*>[\s]*[\n]?"
		t_s = "<" & Chr(37) & "End If" & Chr(37) & ">"
		p_s = s_regex.Replace(p_s,t_s)
		jxIf_ = p_s
	End Function
	
	'''解析Redirect标签
	'属性url,跳转的目标,支持变量
	'属性condition,跳转的条件,仅支持返回bool类型的变量/常量/函数/运算。如果condition为空则直接进行跳转
	'对于复杂条件跳转,请使用asp标签
	'p_s:要解析的模板代码
	Private Function jxRedirect_(Byval p_s)
		Dim t_m, t_mc, t_url, t_condition, t_s
		s_regex.Pattern = "<redirect[\s]+([^>]*)[\s]*>[\s]*[\n]?"		
		Set t_mc = s_regex.Execute(p_s)
		For Each t_m In t_mc
			t_url = getAttr_(t_m.SubMatches(0), "url", "")
			If Left(t_url,1) = "$" Then
				t_url = toVar_(t_url)
			Else
				t_url = Chr(34) & t_url & Chr(34)
			End If
			t_condition = toVar_(getAttr_(t_m.SubMatches(0), "condition", ""))
			If t_url = "" Then
				Sa.E.Throw(61)
			End If
			If t_condition = "" Then
				t_s = "<" & Chr(37) & "Response.Redirect(" & t_url & ")" & Chr(37)  & ">"
			Else
				t_s = "<" & Chr(37) & "If " & t_condition & " Then Response.Redirect(" & t_url & ") End If" & Chr(37)  & ">"
			End If
			p_s = Replace(p_s, t_m.Value, t_s)
		Next
		Set t_mc = Nothing
		jxRedirect_ = p_s
	End Function
	
	'''解析Else标签
	'Else属于公用标签,需要进行统一解析处理
	'p_s:要解析的模板代码
	Private Function jxElse_(Byval p_s)
		s_regex.Pattern = "<[\s]*else[\s]*[\/]{1}[\s]*>[\s]*[\n]?"
		Dim t_s : t_s = "<" & Chr(37) & "Else" & Chr(37) & ">"
		p_s = s_regex.Replace(p_s,t_s)
		jxElse_ = p_s
	End Function
	
	'''解析Asp标签,用于输出asp语句
	'p_s:要解析的模板代码
	Private Function jxAsp_(Byval p_s)
		s_regex.Pattern = "<asp[\s]*>(((?!<asp(.|\n))(.|\n)(?!asp>))+)<\/asp>"
		t_s = "<" & Chr(37) & vbcrlf & "$1" & vbcrlf & Chr(37)  & ">"
		jxAsp_ = s_regex.Replace(p_s,t_s)
	End Function
	
	'''解析简单赋值标签
	'p_s:要解析的模板代码
	Private Function jxStr_(Byval p_s)
		s_regex.Pattern = "\{\$([^\}]*)\}"
		Dim t_mc : Set t_mc = s_regex.Execute(p_s)
		Dim t_s, t_m
		For Each t_m In t_mc
			t_s = t_m.SubMatches(0)
			'还原双引号和单引号
			t_s = Replace(t_s, s_dqmarkstr, """")
			t_s = Replace(t_s, s_sqmarkstr, "'")
			t_s = "<" & Chr(37) & "Response.Write(" & t_s & ")" & Chr(37) & ">"
			p_s = Replace(p_s, t_m.Value, t_s)
		Next
		Set t_mc = NoThing
		jxStr_ = p_s
	End Function
	
	'''解析模板,返回处理结果
	'p_s:要解析的模板代码
	Public Function Resolve(Byval p_s)
		Dim t_s : t_s = p_s
		'最先应该收集Literal标签
		t_s = sjLiteral_(t_s)
		'include标签优先解析
		t_s = jxInclude_(t_s)
		t_s = jxSwitch_(t_s)
		t_s = jxCompare_(t_s)
		t_s = jxRange_(t_s)
		t_s = jxEmpty_(t_s)
		t_s = jxIf_(t_s)
		t_s = jxElse_(t_s)
		t_s = jxFor_(t_s)
		t_s = jxForEach_(t_s)
		t_s = jxRecord_(t_s)
		t_s = jxConst_(t_s)
		t_s = jxDim_(t_s)
		t_s = jxRedirect_(t_s)
		t_s = jxAsp_(t_s)
		t_s = jxStr_(t_s)
		'还原Literal标签必须放在最后
		t_s = hfLiteral_(t_s)
		Resolve = t_s
	End Function
End Class
%>